home *** CD-ROM | disk | FTP | other *** search
/ Aminet 3 / Aminet 3 - July 1994.iso / Aminet / util / misc / aterminfo.lha / comp_scan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-12  |  8.0 KB  |  412 lines

  1.  
  2. /* This work is copyrighted. See COPYRIGHT.OLD & COPYRIGHT.NEW for   *
  3. *  details. If they are missing then this copy is in violation of    *
  4. *  the copyright conditions.                                        */
  5.  
  6. /*
  7.  *    comp_scan.c --- Lexical scanner for terminfo compiler.
  8.  *
  9.  */
  10.  
  11. #include <stdarg.h>
  12. #include <stdio.h>
  13. #include <ctype.h>
  14. #include "compiler.h"
  15.  
  16. #define iswhite(ch)    (ch == ' '  ||  ch == '\t')
  17.  
  18. static int    first_column;        /* See 'next_char()' below */
  19.  
  20. extern void panic_mode(char);
  21.  
  22. /*
  23.  *    int
  24.  *    get_token()
  25.  *
  26.  *    Scans the input for the next token, storing the specifics in the
  27.  *    global structure 'curr_token' and returning one of the following:
  28.  *
  29.  *        NAMES        A line beginning in column 1.  'name'
  30.  *                will be set to point to everything up to
  31.  *                but not including the first comma on the line.
  32.  *        BOOLEAN        An entry consisting of a name followed by
  33.  *                a comma.  'name' will be set to point to the
  34.  *                name of the capability.
  35.  *        NUMBER        An entry of the form
  36.  *                    name#digits,
  37.  *                'name' will be set to point to the capability
  38.  *                name and 'valnumber' to the number given.
  39.  *        STRING        An entry of the form
  40.  *                    name=characters,
  41.  *                'name' is set to the capability name and
  42.  *                'valstring' to the string of characters, with
  43.  *                input translations done.
  44.  *        CANCEL        An entry of the form
  45.  *                    name@,
  46.  *                'name' is set to the capability name and
  47.  *                'valnumber' to -1.
  48.  *        EOF        The end of the file has been reached.
  49.  *
  50.  */
  51.  
  52. int
  53. get_token()
  54. {
  55. long        number;
  56. int        type;
  57. int        ch;
  58. static char    buffer[1024];
  59. char        *ptr;
  60. int        dot_flag = FALSE;
  61.  
  62.     while ((ch = next_char()) == '\n'  ||  iswhite(ch))
  63.         ;
  64.  
  65.     if (ch == EOF)
  66.         type = EOF;
  67.     else
  68.     {
  69.         if (ch == '.')
  70.         {
  71.         dot_flag = TRUE;
  72.  
  73.         while ((ch = next_char()) == ' '  ||  ch == '\t')
  74.             ;
  75.         }
  76.  
  77.         if (! isalnum(ch))
  78.         {
  79.          warning("Illegal character - '%c'", ch);
  80.          panic_mode(',');
  81.         }
  82.  
  83.         ptr = buffer;
  84.         *(ptr++) = ch;
  85.  
  86.         if (first_column)
  87.         {
  88.         while ((ch = next_char()) != ',' && ch != '\n' && ch != EOF)
  89.             *(ptr++) = ch;
  90.  
  91.         if (ch == EOF)
  92.             err_abort("Premature EOF");
  93.         else if (ch == '\n') {
  94.             warning("Newline in middle of terminal name");
  95.             panic_mode(',');
  96.         }
  97.  
  98.         *ptr = '\0';
  99.         curr_token.tk_name = buffer;
  100.         type = NAMES;
  101.         }
  102.         else
  103.         {
  104.         ch = next_char();
  105.         while (isalnum(ch))
  106.         {
  107.             *(ptr++) = ch;
  108.             ch = next_char();
  109.         }
  110.  
  111.         *ptr++ = '\0';
  112.         switch (ch)
  113.         {
  114.             case ',':
  115.             curr_token.tk_name = buffer;
  116.             type = BOOLEAN;
  117.             break;
  118.  
  119.             case '@':
  120.             if (next_char() != ',')
  121.                 warning("Missing comma");
  122.             curr_token.tk_name = buffer;
  123.             type = CANCEL;
  124.             break;
  125.  
  126.             case '#':
  127.             number = 0;
  128.             while (isdigit(ch = next_char()))
  129.                 number = number * 10 + ch - '0';
  130.             if (ch != ',')
  131.                 warning("Missing comma");
  132.             curr_token.tk_name = buffer;
  133.             curr_token.tk_valnumber = number;
  134.             type = NUMBER;
  135.             break;
  136.  
  137.             case '=':
  138.             ch = trans_string(ptr);
  139.             if (ch != ',')
  140.                 warning("Missing comma");
  141.             curr_token.tk_name = buffer;
  142.             curr_token.tk_valstring = ptr;
  143.             type = STRING;
  144.             break;
  145.  
  146.             default:
  147.             /* just to get rid of the compiler warning */
  148.             type = UNDEF;
  149.             warning("Illegal character - '%x'", ch);
  150.         }
  151.         } /* end else (first_column == FALSE) */
  152.     } /* end else (ch != EOF) */
  153.  
  154.     if (dot_flag == TRUE)
  155.         DEBUG0(8, "Commented out ");
  156.  
  157.     if (debug_level >= 8)
  158.     {
  159.         fprintf(stderr, "Token: ");
  160.         switch (type)
  161.         {
  162.         case BOOLEAN:
  163.             fprintf(stderr, "Boolean;  name='%s'\n",
  164.                                                           curr_token.tk_name);
  165.             break;
  166.  
  167.         case NUMBER:
  168.             fprintf(stderr, "Number; name='%s', value=%d\n",
  169.                 curr_token.tk_name, curr_token.tk_valnumber);
  170.             break;
  171.  
  172.         case STRING:
  173.             fprintf(stderr, "String; name='%s', value='%s'\n",
  174.                 curr_token.tk_name, curr_token.tk_valstring);
  175.             break;
  176.  
  177.         case CANCEL:
  178.             fprintf(stderr, "Cancel; name='%s'\n",
  179.                                                           curr_token.tk_name);
  180.             break;
  181.  
  182.         case NAMES:
  183.  
  184.             fprintf(stderr, "Names; value='%s'\n",
  185.                                                           curr_token.tk_name);
  186.             break;
  187.  
  188.         case EOF:
  189.             fprintf(stderr, "End of file\n");
  190.             break;
  191.  
  192.         default:
  193.             warning("Bad token type");
  194.         }
  195.     }
  196.  
  197.     if (dot_flag == TRUE)        /* if commented out, use the next one */
  198.         type = get_token();
  199.  
  200.     return(type);
  201. }
  202.  
  203.  
  204. /*
  205.  *    char
  206.  *    next_char()
  207.  *
  208.  *    Returns the next character in the input stream.  Comments and leading
  209.  *    white space are stripped.  The global state variable 'firstcolumn' is
  210.  *    set TRUE if the character returned is from the first column of the input
  211.  *     line.  The global variable curr_line is incremented for each new line.
  212.  *    The global variable curr_file_pos is set to the file offset of the
  213.  *    beginning of each line.
  214.  *
  215.  */
  216.  
  217. int    curr_column = -1;
  218. char    line[1024];
  219.  
  220. char
  221. next_char()
  222. {
  223.     char    *rtn_value;
  224.     long    ftell();
  225.  
  226.     if (curr_column < 0  ||  curr_column > 1023  ||
  227.         line[curr_column] == '\0')
  228.     {
  229.         do
  230.         {
  231.         curr_file_pos = ftell(curr_fh);
  232.  
  233.         if ((rtn_value = fgets(line, 1024, curr_fh)) != NULL)
  234.             curr_line++;
  235.         } while (rtn_value != NULL  &&  line[0] == '#');
  236.  
  237.         if (rtn_value == NULL)
  238.         return (EOF);
  239.  
  240.         curr_column = 0;
  241.         while (iswhite(line[curr_column]))
  242.         curr_column++;
  243.     }
  244.  
  245.     if (curr_column == 0  &&  line[0] != '\n')
  246.         first_column = TRUE;
  247.     else
  248.         first_column = FALSE;
  249.  
  250.     return (line[curr_column++]);
  251. }
  252.  
  253.  
  254. void backspace()
  255. {
  256.     curr_column--;
  257.  
  258.     if (curr_column < 0)
  259.         syserr_abort("Backspaced off beginning of line");
  260. }
  261.  
  262.  
  263. /*
  264.  *    reset_input()
  265.  *
  266.  *    Resets the input-reading routines.  Used after a seek has been done.
  267.  *
  268.  */
  269.  
  270. void reset_input()
  271. {
  272.     curr_column = -1;
  273. }
  274.  
  275.  
  276. /*
  277.  *    char
  278.  *    trans_string(ptr)
  279.  *
  280.  *    Reads characters using next_char() until encountering a comma, newline
  281.  *    or end-of-file.  The returned value is the character which caused
  282.  *    reading to stop.  The following translations are done on the input:
  283.  *
  284.  *        ^X  goes to  ctrl-X (i.e. X & 037)
  285.  *        {\E,\n,\r,\b,\t,\f}  go to
  286.  *            {ESCAPE,newline,carriage-return,backspace,tab,formfeed}
  287.  *        {\^,\\}  go to  {carat,backslash}
  288.  *        \ddd (for ddd = up to three octal digits)  goes to the character ddd
  289.  *
  290.  *        \e == \E
  291.  *        \0 == \200
  292.  *
  293.  */
  294.  
  295. char
  296. trans_string(ptr)
  297. char    *ptr;
  298. {
  299.     register int    count = 0;
  300.     int        number;
  301.     int        i;
  302.         char        ch;
  303.  
  304.     while ((ch = next_char()) != ','  &&  ch != EOF)
  305.     {
  306.         if (ch == '^')
  307.         {
  308.         ch = next_char();
  309.         if (ch == EOF)
  310.             err_abort("Premature EOF");
  311.  
  312.         if (! isprint(ch))
  313.         {
  314.             warning("Illegal ^ character - '%c'", ch);
  315.         }
  316.         *(ptr++) = ch & 037;
  317.         }
  318.         else if (ch == '\\')
  319.         {
  320.         ch = next_char();
  321.         if (ch == EOF)
  322.             err_abort("Premature EOF");
  323.  
  324.         if (ch >= '0'  &&  ch <= '7')
  325.         {
  326.             number = ch - '0';
  327.             for (i=0; i < 2; i++)
  328.             {
  329.             ch = next_char();
  330.             if (ch == EOF)
  331.                 err_abort("Premature EOF");
  332.  
  333.             if (ch < '0'  ||  ch > '7')
  334.             {
  335.                 backspace();
  336.                 break;
  337.             }
  338.  
  339.             number = number * 8 + ch - '0';
  340.             }
  341.  
  342.             if (number == 0)
  343.             number = 0200;
  344.             *(ptr++) = (char) number;
  345.         }
  346.         else
  347.         {
  348.             switch (ch)
  349.             {
  350.             case 'E':
  351.             case 'e':    *(ptr++) = '\033';    break;
  352.  
  353.             case 'l':
  354.             case 'n':    *(ptr++) = '\n';    break;
  355.  
  356.             case 'r':    *(ptr++) = '\r';    break;
  357.  
  358.             /*case 'b':    *(ptr++) = '\008';    break;*/
  359.             case 'b':    *(ptr++) = '\010';    break;
  360.  
  361.             case 's':    *(ptr++) = ' ';        break;
  362.  
  363.             case 'f':    *(ptr++) = '\014';    break;
  364.  
  365.             case 't':    *(ptr++) = '\t';    break;
  366.  
  367.             case '\\':    *(ptr++) = '\\';    break;
  368.  
  369.             case '^':    *(ptr++) = '^';        break;
  370.  
  371.             case ',':    *(ptr++) = ',';        break;
  372.  
  373.             case ':':    *(ptr++) = ':';        break;
  374.  
  375.             default:
  376.                 warning("Illegal character in \\ sequence");
  377.                 *(ptr++) = ch;
  378.             } /* endswitch (ch) */
  379.         } /* endelse (ch < '0' ||  ch > '7') */
  380.         } /* end else if (ch == '\\') */
  381.         else
  382.         {
  383.         *(ptr++) = ch;
  384.         }
  385.  
  386.         count ++;
  387.  
  388.         if (count > 500)
  389.         warning("Very long string found.  Missing comma?");
  390.     } /* end while */
  391.  
  392.     *ptr = '\0';
  393.  
  394.     return(ch);
  395. }
  396.  
  397. /*
  398.  * Panic mode error recovery - skip everything until a "ch" is found.
  399.  */
  400. void panic_mode(char ch)
  401. {
  402.     int c;
  403.  
  404.     for (;;) {
  405.         c = next_char();
  406.         if (c == ch)
  407.             return;
  408.         if (c == EOF);
  409.             return;
  410.     }
  411. }
  412.